import {
  CanActivate,
  Injectable,
  ExecutionContext,
  HttpStatus,
  Logger,
} from '@nestjs/common';
import { HttpErrorByCode } from '@nestjs/common/utils/http-error-by-code.util';
import { InjectRepository } from '@nestjs/typeorm';
import { User } from 'src/entities/user.entity';
import { bearerTokenFromHeaderAuthorization } from 'src/utils/parseHeaderToken';
import { Repository } from 'typeorm';
import jwt_decode from 'jwt-decode';

type JWTDecode = {
  aud: string;
  iss: string;
  iat: number;
  nbf: number;
  exp: number;
  aio: string;
  azp: string;
  azpacr: string;
  name: string;
  oid: string;
  preferred_username: string;
  rh: string;
  scp: string;
  sub: string;
  tid: string;
  uti: string;
  ver: string;
};

@Injectable()
export class MicrosoftBearerGuard implements CanActivate {
  private logger = new Logger(MicrosoftBearerGuard.name);
  constructor(
    @InjectRepository(User)
    private readonly userRepository: Repository<User>,
  ) {}

  async canActivate(context: ExecutionContext) {
    const request = context.switchToHttp().getRequest();

    const accessToken = bearerTokenFromHeaderAuthorization(
      request.headers['authorization'],
    );
    if (!accessToken) {
      throw new HttpErrorByCode[HttpStatus.UNAUTHORIZED](
        'Access token is missing in the request header.',
      );
    }

    try {
      const decode: JWTDecode = jwt_decode(accessToken);
      const validateUser = await this.userRepository.findOneOrFail({
        where: {
          email: decode.name.includes('@')
            ? decode.name
            : decode.preferred_username,
        },
      });
      request.user = validateUser;

      return true;
    } catch (error) {
      this.logger.error('Error decode: ', error);
      throw new HttpErrorByCode[HttpStatus.UNAUTHORIZED]();
    }
  }
}
